Spike
Spike 是RISC-V官方所推出的ISS (ISA Simulator),以C++所寫成,Spike作為ISA Simulator,為前文所提到的Functional Simulator,注重在行為的正確性,所以不具備統計執行時間等特性,但由於是RISC-V官方所提供的模擬器,且執行速度可達約每秒100MIPS (每秒可執行億個指令),因此常常作為"標準答案"來使用,在製作模擬器時可確認行為是否與Spike結果相同。
如何使用Spike
在開始講Spike之前,我們要先準備一支RISC-V指令編出來的程式才行,俗話說巧婦難為無米之炊,我們在準備好模擬器前需要有一個可以讓他跑的程式,但除非我們的環境本身就是RISC-V的架構否則是沒有辦法直接產生RISC-V的程式的,因此我們會需要先安裝RISC-V官方的toolchain,他可以讓我們在例如x86的電腦編出RISC-V的指令,可以選擇直接去這裡下載官方編好的工具鏈,又或者可以自己從原始碼開始編譯,這部分可以參考高魁良大大的 "與妖精共舞:在 RISC-V 架構上使用 GO 語言實作 binutils 工具包系列 第 2 篇"有非常詳盡的教學,安裝好之後直接寫一個HelloWorld並編譯即可。
riscv64-unknown-elf-gcc -o hello_world.elf main.c
準備好要執行的程式,那我們可以開始編譯Spike了。Spike的編譯過程很簡單,唯一要注意的是Spike本身會使用的device-tree-compiler(dtc)的功能,因此也要先安裝dtc。(關於dtc在後面的章節會再說明)
# install dtc
sudo apt install device-tree-compiler
git clone https://github.com/riscv-software-src/riscv-isa-sim.git
cd riscv-isa-sim
# check out to v1.1.0 (last release ver.)
git checkout v1.1.0
mkdir build
cd build
../configure
make -j
編好了Spike,那我們接下來就可以開始執行RISC-V的程式啦,不過此時我們開心的./spike hello_wrold.elf,卻發現沒有辦法順利執行,這是為什麼呢!?
PK (Proxy kernel)
Spike有一個配套的假kernel叫做PK,他的主要目的是幫忙Spike在沒有真正的OS(例如linux)的環境下去做一切Linux該做的事情,因此如果沒有PK的話例如semi-hosting (簡單來說就是開讀檔、印出文字到螢幕上)或者是虛擬記憶體的配置等事情都沒有辦法進行,看到這裡大家應該就明白為什麼沒有辦法順利執行HelloWorld了吧。那假設不想要印東西,只想要讓Spike跑一個baremetal的程式可以嗎,理論上是可以的,但是因為Spike會在程式開始跑之前安插一小段ROM code,這裡推測是為了模擬真實的硬體的開機流程 (關於linux開機流程可以參考這個影片)
sim.cc
...
..
start_pc = start_pc == reg_t(-1) ? get_entry_point() : start_pc;
uint32_t reset_vec[reset_vec_size] = {
0x297, // auipc t0,0x0
0x28593 + (reset_vec_size * 4 << 20), // addi a1, t0, &dtb
0xf1402573, // csrr a0, mhartid
get_core(0)->get_xlen() == 32 ?
0x0182a283u : // lw t0,24(t0)
0x0182b283u, // ld t0,24(t0)
0x28067, // jr t0
0,
(uint32_t) (start_pc & 0xffffffff),
(uint32_t) (start_pc >> 32)
};
這段程式碼會將dtb (前面提到dtc的產物的位置儲存在a1,將目前的cpu編號存在a0後跳到預設的pc位置,這裡是設定為0x80000000),因此除非我們特別去修改spike的rom段,又或者是我們執行的程式的entry point恰好是0x80000000,否則是沒有辦法正常執行的。
我們可以走正規的方法,使用pk來執行該程式,pk的安裝方法與Spike相當接近,流程如下。
git clone https://github.com/riscv/riscv-pk.git
cd riscv-pk
mkdir build
cd build
#prefix設定安裝路徑,host決定使用的toolchain
../configure --prefix=$RISCV --host=riscv64-unknown-elf
make
make install
之後我們只透過Spike執行pk,並將欲執行的程式作為pk的參數即可正常執行。
./spike /path/to/pk hello_world.elf
>HelloWorld
這裡有一個可以注意的地方,那就是pk在編譯的時候會需要使用risc-v的toolchain,但Spike卻不用,這是因為Spike是作為一支x86(或任何原生架構)上面的程式,而PK則是執行在Spike上面的risc-v程式。
以上大概就是Spike的基本介紹及使用,其實Spike還有一些蠻不錯的功能,例如log或者是debug模式等,這部份等後續有使用到的時候再帶著大家操作~
碎碎念:Spike應該是大部分接觸risc-v的人會先碰過的工具吧,我也趁這個機會複習了一下Spike的使用方法,明天來試著聊聊看QEMU